package io.github.wanggit.antrpc.demos.circuit_breaker.circuit_breaker_provider;

import com.vladsch.flexmark.ext.abbreviation.AbbreviationExtension;
import com.vladsch.flexmark.ext.tables.TablesExtension;
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.data.MutableDataSet;

import java.util.Arrays;

public class Test {

    public static void main(String[] args) {
        MutableDataSet options = new MutableDataSet();
        options.set(Parser.EXTENSIONS, Arrays.asList(TablesExtension.create(), AbbreviationExtension.create()));
        Parser parser = Parser.builder(options).build();
        HtmlRenderer renderer = HtmlRenderer.builder(options).build();

        // You can re-use parser and renderer instances
        Node document = parser.parse("# AntRPC控制台\n" +
                "## 介绍\n" +
                "AntRPC控制台提供了RPC服务接口的管理能力，如下所示：\n" +
                "1. 接口上下线；\n" +
                "2. 接口调用频率控制；\n" +
                "3. 接口权重设置；\n" +
                "4. 接口修改负载均衡策略；\n" +
                "5. 接口测试；\n" +
                "6. 接口调用情况统计；\n" +
                "7. Zookeeper节点可视化；\n" +
                "8. 应用拓扑结构图；\n" +
                "9. 调用日志；\n" +
                "10. 配置中心；\n" +
                "## 安装教程\n" +
                "### 从源码安装\n" +
                "下载源码之后，修改`application.properties`配置文件：\n" +
                "1. `antrpc.zookeeper`配置Zookeeper地址，多个使用逗号间隔；\n" +
                "2. `antrpc.service.codec.type`如果服务接口间传输数据是加密的，那么需要配置加密类型。默认为`io.github.wanggit.antrpc.commons.codec.cryption.NoOpCodec`不做加密；可以设置为`io.github.wanggit.antrpc.commons.codec.cryption.AESCodec`做AES加密；\n" +
                "3. `antrpc.service.codec.key`如果要使用AES加解密，那么在这一项配置AES加解密的Key；\n" +
                "4. `antrpc.default.load.balancer`设置默认的负载均衡器，可用的负载均衡器包含：`io.github.wanggit.antrpc.client.zk.lb.RandomLoadBalancer`和`io.github.wanggit.antrpc.client.zk.lb.RoundLoadBalancer`；\n" +
                "5. `antrpc.elasticsearch.hosts`设置保存调用日志的ElasticSearch地址，多个地址使用逗号间隔；\n" +
                "6. `antrpc.elasticsearch.username`设置Elasticsearch用户名；\n" +
                "7. `antrpc.elasticsearch.password`设置Elasticsearch密码；\n" +
                "8. `spring.datasource.url`数据库URL配置；\n" +
                "9. `spring.datasource.username`数据库用户名；\n" +
                "10. `spring.datasource.password`数据库密码；\n" +
                "11. `console.default.user-name`配置用于登录控制台的用户名；\n" +
                "12. `console.default.password`配置用于登录控制台的密码；\n" +
                "\n" +
                "修改配置文件之后，通过`mvn clean package`或`./mvnw clean package`命令打war包。如果要取消打war包时的测试用例，那么可以添加`-DskipTests`参数。\n" +
                "为了更高的查询效率，可以在数据库中执行以下SQL，添加索引。\n" +
                "```sql\n" +
                "ALTER TABLE `consumer_rate_limiting`\n" +
                "\tADD INDEX `class_md5_idx` (`class_md5`);\n" +
                "\n" +
                "ALTER TABLE `provider_rate_limiting`\n" +
                "\tADD INDEX `class_md5_idx` (`class_md5`);\n" +
                "```\n" +
                "最后使用以前命令运行控制台\n" +
                "```shell\n" +
                "java -jar console-0.0.1.war\n" +
                "```\n" +
                "```shell\n" +
                "nohup java -jar console-0.0.1.war > console.log 2>&1 &\n" +
                "```\n" +
                "### 通过Docker安装\n" +
                "通过执行以下脚本启动Docker。\n" +
                "```shell\n" +
                "docker pull wanggmail/antrpc_console:0.0.1\n" +
                "# application args\n" +
                "app_args=\"-Dconsole.default.password=admin_password \\\n" +
                "    -Dconsole.default.user-name=admin \\\n" +
                "    -Dantrpc.zookeeper=127.0.0.1:2181 \\\n" +
                "    -Dantrpc.elasticsearch.hosts=127.0.0.1:9200 \\\n" +
                "    -Dspring.datasource.url=jdbc:mysql://127.0.0.1:3306/antrpc_console?useUnicode=true&characterEncoding=utf8&useSSL=false \\\n" +
                "    -Dspring.datasource.username=root \\\n" +
                "    -Dspring.datasource.password=mysql_password\"\n" +
                "# java jvm args\n" +
                "java_opts=\"-Xmx1280m -Xms1280m\"\n" +
                "docker run --name antrpc_console \\\n" +
                "    -v /root/logs:/root/logs \\\n" +
                "    -e \"APP_ARGS=$app_args\" \\\n" +
                "    -e \"JAVA_OPTS=$java_opts\" \\\n" +
                "    -d wanggmail/antrpc_console:0.0.1\n" +
                "```\n" +
                "更多的`application args`设置，可以参见上面的配置文件说明。\n" +
                "\n" +
                "### 通过Docker Compose安装\n" +
                "如果要快速搭建AntRPC的整套环境，可以使用`docker-compose`。\n" +
                "1. 在当前目录下新建`mysql_init`文件夹，并下载控制台的 [数据库初始化脚本](src/main/docker/mysql_init/database.sql) 放在此文件夹下；\n" +
                "2. [下载控制台的`docker-compose.yml`文件](src/main/docker/docker-compose.yml)到`mysql_init`同级位置；\n" +
                "3. 修改`docker-compose.yml`文件中`antrpc_console`的`APP_ARGS`参数，以修改控制台的用户名与密码；\n" +
                "4. 修改`docker-compose.yml`文件中`kafka`的`KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://172.16.101.19:9092`配置，如果需要外网访问此`kafka`，那么此IP修改为外网IP；如果只是内网访问，那么此IP修改为内网IP。\n" +
                "5. 再执行`docker-compose up`命令启动整套环境。\n" +
                "\n" +
                "修改密码如下图所示：\n" +
                "\n" +
                "![修改密码](readme_images/update_console_pwd.png)\n" +
                "\n" +
                "修改`kafka`配置如下图所示：\n" +
                "\n" +
                "![修改kafka配置](readme_images/docker-compose-update-kafka-ip.png)\n" +
                "\n" +
                "存放`mysql_init`文件夹与`docker-compose.yml`文件夹的目录结构如下所示：\n" +
                "\n" +
                "![](readme_images/docker-compose-desc.png)\n" +
                "\n" +
                "**在Windows系统环境下，由于要启动的docker数据量较多，如果在启动时出现磁盘使用率超高的情况。是因为系统分配给Docker的内存太少，导致频繁的swap造成的，可以如下图所示调整内存。**\n" +
                "\n" +
                "![](readme_images/docker_change_resources.png)\n" +
                "\n" +
                "## 使用说明\n" +
                "点击`应用拓扑`和`调用日志`两个菜单时，控制台的日志中会报错`org.elasticsearch.ElasticsearchStatusException: Elasticsearch exception [type=index_not_found_exception, reason=no such index [call_logs]]`\n" +
                "是因为elasticsearch中还没有收集到日志，所以索引还未自动创建，在接收到日志之后，就不会出现这个问题。所以此问题可以忽略。\n" +
                "### 登录\n" +
                "![登录](readme_images/login.png)\n" +
                "\n" +
                "### 接口列表\n" +
                "![接口列表](readme_images/interface_list.png)\n" +
                "\n" +
                "### 方法列表\n" +
                "![方法列表](readme_images/method_list.png)\n" +
                "\n" +
                "### 测试方法\n" +
                "![测试方法](readme_images/method_test.png)\n" +
                "\n" +
                "测试接口参数格式说明：\n" +
                "1. 多个参数时，按方法实际参数列表顺序排列；\n" +
                "2. 多个参数时，以` $$ `进行间隔，比如`wanggang $$ yxf`；\n" +
                "3. 集合类参数以`json`格式传入，比如`[1,2,3,4]`；\n" +
                "4. Map与对象类参数以`json`格式传入，比如`{\"name\": \"wanggang\"}`；\n" +
                "5. 集合与对象类参数嵌套以`json`格式传入，比如`[{\"name\": \"wanggnag\"}, {\"name\": \"yxf\"}]`；\n" +
                "\n" +
                "### 修改方法限流\n" +
                "![修改方法限流](readme_images/method_rate_limit.png)\n" +
                "\n" +
                "限流说明：\n" +
                "1. 限流分为两种，服务提供者限流与服务消费者限流；\n" +
                "2. 服务消费者限流，表示此服务消费此接口时限定自身的调用频率；\n" +
                "3. 服务提供者限流，表示此服务提供者允许其他节点调用接口的频率；\n" +
                "4. 服务提供者限流设置优先级大于服务消费者设置，比如服务消费者设置`5/10`表示10秒内可调用5次，服务提供者设置`3/10`表示10秒内可调用3次，那么所有服务消费者都会共同受限于服务提供者设置的`3/10`；\n" +
                "5. 调用达到限流信息时并且**未设置失败默认回调**时，会抛出`io.github.wanggit.antrpc.client.spring.OnFailHolder.NotFoundOnFailHandlerException`；\n" +
                "\n" +
                "设置失败默认回调如下所示：如果远程调用`FishInterface`失败，那么就会在本地的Spring容器中找以下Bean进行调用；\n" +
                "```java\n" +
                "    @RpcService\n" +
                "    interface FishInterface extends AnimalInterface {\n" +
                "        @RpcMethod\n" +
                "        String eat();\n" +
                "    }\n" +
                "    \n" +
                "    @OnRpcFail(clazz = FishInterface.class)\n" +
                "    public static class DefaultMyFish implements FishInterface {\n" +
                "\n" +
                "        @Override\n" +
                "        public String getType() {\n" +
                "            return \"default dog type\";\n" +
                "        }\n" +
                "\n" +
                "        @Override\n" +
                "        public String eat() {\n" +
                "            return \"default dog eat\";\n" +
                "        }\n" +
                "    }\n" +
                "```\n" +
                "![修改方法限流](readme_images/method_rate_limit_update.png)\n" +
                "\n" +
                "### 接口详情\n" +
                "![接口详情](readme_images/interface_details.png)\n" +
                "\n" +
                "### 修改接口权重\n" +
                "![修改接口权重](readme_images/update_interface_weights.png)\n" +
                "\n" +
                "### 方法调用情况统计\n" +
                "![方法调用情况统计](readme_images/method_call_stats.png)\n" +
                "\n" +
                "### Zookeeper节点可视化\n" +
                "![Zookeeper节点可视化](readme_images/zookeeper_node_list.png)\n" +
                "![Zookeeper节点数据](readme_images/zookeeper_node_data.png)\n" +
                "\n" +
                "### 服务拓扑图，依据最近1小时调用记录生成\n" +
                "![服务拓扑图](readme_images/service_tuo_pu.png)\n" +
                "\n" +
                "### 调用日志，更多分析建议使用kibana\n" +
                "![调用日志](readme_images/service_call_logs.png)\n" +
                "\n" +
                "### 调用日志图谱\n" +
                "![调用日志图谱](readme_images/service_call_logs_graph.png)\n" +
                "\n" +
                "### 调用日志图谱查看节点数据\n" +
                "![调用日志图谱查看节点数据](readme_images/service_call_logs_graph_node_data.png)\n" +
                "\n" +
                "### 配置中心\n" +
                "AntRPC的配置由三级组成：**环境、服务名或空间、配置项**。系统默认的环境为`default`，环境建议可以分为`dev`,`test`,`prod`。\n" +
                "可以通过系统配置`antrpc.config-env`指定环境。每个项目默认会订阅环境下的服务名，\n" +
                "如果一个服务名称为`product_service`，配置环境为`prod`，\n" +
                "那么会默认为订阅`prod/product_service`下的所有配置。多个服务的公用配置可以创建空间，一个服务可以订阅多个空间。比如新建redis配置的空间`redis_commons_space`，\n" +
                "与mq配置`mq_commons_space`，那么其他的服务都可以通过配置`antrpc.config-shared-spaces=redis_commons_space, mq_commons_space`订阅得到redis与mq的公用配置。\n" +
                "\n" +
                "在不同环境下的相同配置项不会相互覆盖，**覆盖优先级：服务级配置 > 空间级配置 > 本地配置**。\n" +
                "比如：服务`product_service`有如下配置。\n" +
                "1. 服务的`application.properties`配置文件中配置`config.test.name=wanggang`;\n" +
                "2. 在配置中心一个共享空间下配置`prod/commons_space/config.test.name=yy`;\n" +
                "3. 由于优先级关系，此时系统中生效的配置是`config.test.name=yy`;\n" +
                "4. 在配置中心服务名下配置`prod/product_service/config.test.name=yxf`;\n" +
                "5. 由于优先级关系，此时系统中生效的配置是`config.test.name=yxf`;\n" +
                "6. 在配置中心删除`prod/product_service/config.test.name=yxf`，由于优先级关系，系统中的配置回退到`config.test.name=yy`;\n" +
                "7. 在配置中心再删除`prod/commons_space/config.test.name=yy`，由于优先级关系，系统中的配置回退到`config.test.name=wanggang`;\n" +
                "\n" +
                "#### 配置中心环境列表\n" +
                "![配置中心环境列表](readme_images/config_env_list.png)\n" +
                "\n" +
                "#### 配置中心空间列表\n" +
                "![配置中心空间列表](readme_images/config_env_space_list.png)\n" +
                "\n" +
                "#### 配置中心拷贝配置项到新空间\n" +
                "![拷贝配置项到新空间](readme_images/config_copy_space_to.png)\n" +
                "\n" +
                "#### 配置中心Keys列表\n" +
                "![Keys列表](readme_images/config_env_keys_list.png)\n" +
                "\n" +
                "从上图可以看出，配置中心提供了单条新建Key-Value与批量新建Key-Value的方法；\n" +
                "\n" +
                "#### 配置中心单条新建Key-Value\n" +
                "![单条新建Key-Value](readme_images/config_single_add_key_values.png)\n" +
                "\n" +
                "#### 配置中心批量新建Key-Value\n" +
                "![批量新建Key-Value](readme_images/config_batch_add_key_values.png)\n" +
                "\n" +
                "#### 配置中心查看Key详情\n" +
                "![查看Key详情](readme_images/config_list_keys_details.png)\n" +
                "\n" +
                "#### 配置中心模糊查询\n" +
                "![模糊查询](readme_images/config_keys_fuuzy_query.png)\n" +
                "\n");
        String html = renderer.render(document);  // "<p>This is <em>Sparta</em></p>\n"
        System.out.println(html);
    }

}
